package com.zhouyu.gamecommunity.utils;

import cn.hutool.core.net.NetUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;

public class UDPUtil {
    private static final Log log = LogFactory.get();

    // 默认缓冲区大小
    private static final int DEFAULT_BUFFER_SIZE = 1024;

    /**
     * 发送UDP消息
     * @param host 目标主机地址
     * @param port 目标端口
     * @param message 要发送的消息
     * @throws IOException 发送失败时抛出异常
     */
    public static void send(String host, int port, String message) throws IOException {
        send(InetAddress.getByName(host), port, message);
    }

    /**
     * 发送UDP消息
     * @param address 目标InetAddress
     * @param port 目标端口
     * @param message 要发送的消息
     * @throws IOException 发送失败时抛出异常
     */
    public static void send(InetAddress address, int port, String message) throws IOException {
        if (message == null) {
            throw new IllegalArgumentException("消息不能为空");
        }
        byte[] data = message.getBytes(StandardCharsets.UTF_8);
        try (DatagramSocket socket = new DatagramSocket()) {
            DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
            socket.send(packet);
            System.out.println("UDP消息发送成功");
            log.debug("UDP消息发送成功: {}:{} -> {}", address.getHostAddress(), port, message);
        }
    }
    /**
     * 接收UDP消息（阻塞方式）
     * @param port 监听端口
     * @return 接收到的消息
     * @throws IOException 接收失败时抛出异常
     */
    public static String receive(int port) throws IOException {
        return receive(port, DEFAULT_BUFFER_SIZE);
    }

    /**
     * 接收UDP消息（阻塞方式）
     * @param port 监听端口
     * @param bufferSize 缓冲区大小
     * @return 接收到的消息
     * @throws IOException 接收失败时抛出异常
     */
    public static String receive(int port, int bufferSize) throws IOException {
        if (bufferSize <= 0) {
            bufferSize = DEFAULT_BUFFER_SIZE;
        }

        byte[] buffer = new byte[bufferSize];
        try (DatagramSocket socket = new DatagramSocket(port)) {
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
            log.debug("开始监听UDP端口: {}", port);
            socket.receive(packet); // 阻塞等待

            String message = new String(packet.getData(), 0, packet.getLength(), StandardCharsets.UTF_8);
            log.debug("收到UDP消息: {}:{} -> {}", packet.getAddress().getHostAddress(),
                    packet.getPort(), message);
            return message;
        }
    }

    /**
     * 启动一个线程持续接收UDP消息
     * @param port 监听端口
     * @param handler 消息处理器
     */
    public static void startReceiveLoop(int port, UdpMessageHandler handler) {
        startReceiveLoop(port, DEFAULT_BUFFER_SIZE, handler);
    }
    /**
     * 启动一个线程持续接收UDP消息
     * @param port 监听端口
     * @param bufferSize 缓冲区大小
     * @param handler 消息处理器
     */
    public static void startReceiveLoop(int port, int bufferSize, UdpMessageHandler handler) {
        if (handler == null) {
            throw new IllegalArgumentException("消息处理器不能为空");
        }

        ThreadUtil.execute(() -> {
            try (DatagramSocket socket = new DatagramSocket(port)) {
                byte[] buffer = new byte[bufferSize];
                log.debug("启动UDP持续监听: {}", port);

                while (!Thread.currentThread().isInterrupted()) {
                    DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                    socket.receive(packet);

                    String message = new String(packet.getData(), 0, packet.getLength(),
                            StandardCharsets.UTF_8);
                    String sender = packet.getAddress().getHostAddress() + ":" + packet.getPort();

                    log.debug("收到UDP消息: {} -> {}", sender, message);
                    handler.handle(sender, message);
                }
            } catch (IOException e) {
                log.error("UDP接收循环异常", e);
            }
        });
    }
    /**
     * UDP消息处理器接口
     */
    @FunctionalInterface
    public interface UdpMessageHandler {
        /**
         * 处理接收到的消息
         * @param sender 发送者地址:端口
         * @param message 消息内容
         */
        void handle(String sender, String message);
    }

    /**
     * 检查端口是否可用
     * @param port 端口号
     * @return 端口是否可用
     */
    public static boolean isPortAvailable(int port) {
        return NetUtil.isUsableLocalPort(port);
    }
}
